I believe the next fundamental tool we're going to need to script for our game is the player's flashlight.
When the players are inside of the basement, we need to give them a flashlight that they can pick up
from the floor right here, and we got to make that flashlight functional.
We're also going to have that flashlight slowly drain battery, forcing the players to search for new
batteries throughout the basement.
So let's go ahead and get started.
I've attached this model right here next to the lecture that contains the two animations that we're
going to be using for our flashlight.
So you can go ahead and open up your animation editor on this rig.
And you can go ahead and load the animations that are stored inside of here, which is your idle animation
for the flashlight and the equipped animation for the flashlight.
And they're pretty basic.
That's your equip.
And this is the idle animation which loops forever.
Once you get those animations uploaded and you got the IDs copied, you're going to want to head into
server storage and go to the tools folder.
And you'll go to the flashlight and you'll update them into their respective animations.
So upload the equip animation in here and the idle animation inside of there.
From this point, we can go ahead and open up the flashlight server script and the flashlight local
script.
Now our flashlight, which we have an example of right here, has several parts inside of it.
One of these parts is the light part where our light is going to be emanating out of.
We have an attachment in here that shows the inner circle for the light as well as an outer circle.
And we also have a ring to cast a neat little shadow in the center to make the inner light and the outer
diffused light more distinct from each other.
We also have this surface light restricted to a very small little area, because when it's enabled,
it makes it look like the flashlight is glowing inside.
So for example, if I went and disabled this, as you can see, it doesn't look like the flashlight
is really glowing anymore.
But if I go back and enable it.
And we take a look again.
Now it looks like that our flashlight is glowing more.
Now we already have a script in here for when the players click this flashlight giver, it'll clone
the flashlight tool and put it in their backpack.
And it looks like I named it incorrectly, so I'll just rename it here real quick.
We'll just call it Flashlight Giver script.
This is just a very basic script that we don't need to worry about scripting right now.
It's already completed for us, but the main thing we're going to want to worry about is the flashlight
service script and the flashlight local script.
So inside of the local script, the only service we're going to need is the player service.
And then we can make a whole bunch of references to different variables.
We'll make a reference to the flashlight itself, which will be the script dot parent of this local
script.
We're going to get the guy that's inside of our flashlight, which will display on the screen to show
the player the current battery.
So that is inside of the flashlight.
And since this tool is going to be cloned to their inventory from server storage, we're going to have
to wait for everything to replicate inside of the tool.
So we're going to wait for the flashlight guy inside of our flashlight.
And then we're also going to reference an event inside of the server script of our flashlight, which
we are going to use to tell the server to, you know, enable the flashlight on its end.
So clicked event is equal to flashlight.
And we're going to wait for the flashlight service script, and then we're going to wait for the clicked
event.
From this point, we can make a reference to the local player.
So players dot local player and we're going to get the character of the local player which is equal
to the local player dot character or local player dot character added.
And we'll wait for the player's character in case it doesn't exist.
We're going to get the humanoid of our character, so that's going to be in the character.
Wait for child humanoid.
And they're also going to get the animator.
So in the humanoid we'll wait for child animator.
And we can go ahead and denote this as an animator.
And we can go ahead and denote this as the humanoid.
After that, we can go ahead and load our equip animation so we can call this Equip track.
And we'll use the animator.
And we'll load an animation which is inside of our flashlight wafer child animations, and then wait
for child equip.
And then we're just going to do the exact same thing.
But this time we'll have the idle track and we'll wait for the idle animation.
And since we've already waited for the animations folder up here, we don't have to do it again down
here.
So we can just directly index for the animations folder.
And then we're going to make a reference to the click sound that's inside of the flashlight.
So there's a click on sound which is in the flashlight.
We'll wait for child inside of the handle and we'll wait for the on sound.
And then there's also a click off sound in the same location.
So flashlight dot handle and we'll wait for the off sound.
And then we're going to create two booleans to keep track of different things in the flashlight.
First we're going to have a click debounce to prevent the player from spam turning on and off the flashlight.
And we're also going to verify that on the server as well.
So we'll set this to false by default.
And then we're also going to have a variable to keep track of whether or not the flashlight is on or
off.
So this will be called flashlight on.
And we'll set that to false.
And then from this point we can have a private function to listen for when the flashlight is activated
or the tool is clicked.
So we can call this flashlight activated.
And then inside of the handler section the different events we're going to want to listen to.
First off we want to listen for when our flashlight is equipped.
We'll connect a Lambda function to this.
We want to listen to.
When our flashlight is unequipped.
We'll connect a lambda function to this as well.
We want to listen on our flashlight when an attribute changes, because inside of our flashlight we
have two attributes one that represents the current battery of the flashlight and one that represents
the maximum battery of the flashlight.
And we're going to want to get attribute change signal.
And we want to listen for when the current battery attribute changes.
And when it does we're going to connect a Lambda function to this.
We'll also want to listen for when our flashlight is activated.
And we'll connect our flashlight activated function.
And lastly, we want to listen for when our flashlight is being destroyed.
And the reason for this is if we ever have a server script that destroys the player's tools, like when
they get set to the dead team, then we don't want the guy that we set inside of their player guy folder
to be stuck.
That's a common problem that people have with a lot of tools, because they forget to listen for when
the flashlight is being destroyed, when the flashlight is being destroyed, then the reference that
we made to the guy, we want to go ahead and destroy that guy, no matter where it is, we want to destroy
it.
Okay, so when we equip our flashlight, the first thing we can do is we can set the parent of our guy
equal to the local player dot player guy folder.
We can go ahead and play our equip track.
And then we're also going to play our idle track at the exact same time.
And this is because the animation priority is higher on the equipped track.
So even though we're playing them at the exact same time, this one will play first.
And then once this ends, then this animation will take over.
When our flashlight gets unequipped, we're going to set the g dot parent back into the flashlight.
We're going to stop our equip track just in case it was playing.
And then we're also going to stop our idle track from playing.
Another thing we want to check is whether or not if our flashlight is on.
So if our flashlight is on, then we want to play the click off sound when we unequip our flashlight.
So click off sound and play and then we can set flashlight on equal to false.
Now when the attribute inside of our flashlight changes, then we're going to want to update the guy
that's on our screen.
So what we could do is we could refer to our guy, get the frame.
And there is a text label in there called the current battery label.
And we're going to set the text equal to the flashlight get attribute current battery.
And another thing we want to check in here is if our flashlight get attribute current battery is equal
to zero.
If it is then we want to set flashlight on equal to false.
Now the next function we can fill out is our flashlight activated function.
So when we click we first want to check whether or not our click Debounce is true.
If it is then we're just going to return out of the function.
And then we can set click Debounce equal to true.
And we're going to check if our flashlight is on.
If our flashlight is on in the player clicked.
That means we need to turn off our flashlight.
So flashlight on we're going to set to false.
And then we're going to play the click off sound.
Otherwise, if our flashlight is not on, then we want to turn it on.
So we'll play the click on sound.
And then we'll also set flashlight on equal to true.
After that we can yield for like two seconds, because that's the duration we want to have our cool
down for.
And then we can set click debounce equal to false.
Now, something that's very important now is we need to use our click event to let the server know that
we have activated the tool on our end, so we can do fire server to fire this event.
Now the activated event also works on the server as well.
So there's actually two ways you could do it.
You could either do it through a remote event, or you could just let the server listen to when the
tool is activated.
Technically, either way, it works, but we're going to go ahead and try it out with this remote event.
That way we're just more comfortable with using them.
Now inside of our server script, we're going to need the player service again.
And we're also going to need replicated storage.
We're going to make a reference to the flashlight, which is equal to script dot parent.
And then we're also going to refer to the clicked event which is a child of our script.
So script dot clicked.
We're going to make a reference to the update GUI event.
And we're going to use this to let the player know that, hey, when they run out of battery, we can
give them a small message saying you have no more battery left.
So replicated storage, dot events, dot remotes, dot update guy and then of course we're going to
have to get the GUI actions enum.
So we'll require from replicated storage dot modules dot enums dot gui actions enum.
We're going to make a reference to the inner light inside of our flashlight.
So that's in the flashlight dot light part.
It is an attachment in there.
And we can get the inner light.
And then we're also going to get the outer light.
So that's in the flashlight dot light part dot attachment dot outer.
What we're going to do here is we're going to create a variable called thread.
We're going to set this to nil for now.
But when the flashlight gets equipped and while the flashlight is on, we're going to have a loop that
constantly runs and slowly drains the battery.
And then when the flashlight either runs out of battery or the tools unequipped, that while loop will
either cancel or we will cancel the thread itself when the tool gets unequipped.
We also want a variable to act as a Debounce, so we can call this.
Click Debounce and we'll set this to false.
We'll also have a variable to keep track of whether or not the flashlight is on.
So flashlight on is equal to false.
And then we're also going to have a variable to keep track of when the flashlight was last clicked.
We're going to keep a timestamp of that so we can call it last clicked.
And this is equal to the tick function.
And because this script is going to run immediately and the player might want to turn on their flashlight
immediately, we're going to subtract this tick by two seconds.
Now we can also define some constants for our flashlight.
First off, we want to have a color for when the flashlight is turned on.
So the on color is equal to color three dot from RGB.
And the color that I found best for our flashlight would be 168 on the red, one, 29 on the green,
and then 67 on the blue.
We get this yellowish hue.
And then we also want to define the color for our neon part when the flashlight turns off.
And that's just going to be black.
So color three from RGB 000.
And then we're also going to define the cooldown which is going to be two seconds.
Now of course we're going to need some private functions.
One function is going to change the light.
And we could have a boolean in here like set on to tell this function whether or not we want to change
the lights to be on or off.
We'll have a function to listen to our flashlight event, so we'll just call it Flashlight Event.
And this will get just passed the player that triggered the event.
And then we're also going to have a function and we can call it drain battery.
And this is going to contain the while loop that's going to constantly run to drain the battery.
And inside of the handler section we can listen for when our flashlight is equipped.
We'll connect a lambda function to that.
We can listen to when our flashlight is unequipped.
Connect a function to this as well.
We want to listen for when our clicked event is fired.
So on server event will connect.
Flashlight event.
And then we're also going to want to listen to when the attribute changes on our flashlight.
So get attribute change signal.
And this is going to be the current battery.
And we can connect a function to this.
And we're actually not going to need a main section.
So I'm going to go ahead and delete that.
Okay, so when our flashlight is equipped, the first thing we want to do is call our drain battery
function to start draining the battery when you know the flashlight has no battery in it.
So all we're going to do in here is we're going to have a while loop that runs forever.
And it'll have a yield of we'll say two seconds.
So every two seconds we'll deduct one value off of the current battery.
So it should last a total of 200 seconds with our battery.
And what we're going to do is we're going to check first of all if our flashlight is on.
So if our flashlight is not on then we don't want to drain any battery.
So we'll just continue looping.
If our flashlight, let's say get attribute current battery is somehow less than or equal to zero,
then we're also going to just continue looping.
Otherwise we can set our flashlight the attribute current battery.
And we'll set it to the flashlight, get attribute current battery and subtract that value by one.
And that's all we need to do for our while loop.
So when the flashlight is equipped, we'll use the task dot spawn function to spawn our drain battery
function in a new thread.
And we're going to get that thread returned back to us so we can store it within our thread, uh, variable.
And that way when our flashlight gets unequipped, we can check if thread exists.
So if this thread exists, then we can use the task dot cancel function to stop this while loop from
executing.
Then we can set thread equal to nil and we'll set flashlight on equal to false.
And this is where we would use our change light function to turn off the flashlight.
So in our change light function what we're going to do is we're going to refer to our inner light.
And we're going to set enabled equal to the boolean.
We'll do the same thing for the outer light dot enabled equal to the boolean.
And then our flashlight light part dot color is going to be equal to.
We're going to check set on.
And then we're going to pass on color.
So if set on is true, then the value that gets returned from this and statement is going to be our
on color, which means our color property is going to be set to the correct color.
Or we're going to pass the off color.
So basically we remember we talked about this kind of statement for setting variables.
When set on is equal to true.
The value that gets set here is going to be our on color.
Otherwise if set on evaluates to false then the value that's going to be passed.
Here is our off color.
Alrighty, now the next function we can go ahead and fill out is our flashlight event function.
The first thing we need to check is who exactly fired this event?
Because an exploiter could be firing the events in other players flashlights, so we want to make sure
the player firing this event is the same player that is actually having the flashlight equipped.
So if the player that fired this event is not equal to and we're going to use the player service and
get player from character and we can pass the flashlight dot parent, which should be the character
model.
If this player is not equal to the player who has ownership over the flashlight, then we're just going
to return.
The next thing we're going to check is if the tick, the current tick minus our last tick, or the last
clicked is less than our cooldown.
So if it's been less than two seconds, then we don't want to do anything because we're still waiting,
so we'll just return.
Otherwise we can set last clicked equal to the current tick.
Then we can check if our flashlight is on.
So if it is on and the flashlight event gets fired, then we clearly need to turn off the flashlight.
So flashlight on is going to be set to false.
And then we're going to use our change light function and pass false.
Else if.
Flashlight on is true.
And another condition we want to check is the flashlight get attribute current battery is greater than
zero.
So if the battery is greater than zero, then we're all good to go.
And we can turn on the flashlight.
So flashlight on.
Equal to true and then change light will pass true to that.
Otherwise they are going to be out of battery.
Because if this condition didn't evaluate to true meaning that we do not have enough battery, then
we can use the update GUI event and fire to this particular player here.
So we'll pass the player.
Give the guy actions enum of small message and we can give them a message of like you ran out of batteries.
And then just for a little bit of added protection, we're also going to check if our click Debounce
is true.
If it is, then we're going to return.
And then we can set click Debounce equal to true.
And then we'll go down, and then we're going to yield for our, uh.
What was it?
I believe it was the cooldown.
And then we're going to set click the balance back to false after that cooldown ends.
So we've kind of got double security here.
Technically you could just do one or the other, but why not have more security even if it is a little
redundant?
Now, the last thing we need to fill out is listening to when our current battery attribute changes.
So if the current battery attribute changes, we want to check if the flashlight get attribute current
battery is less than or equal to zero.
If it is, then we need to turn off the flashlight.
So flashlight on.
We're going to set to false.
And then we're going to change light and set that to false as well.
Perfect.
And our flashlight should actually be complete.
So what we could do to test it real quick is I'm going to copy the flashlight and temporarily put it
inside of the starter pack.
And we can go ahead and play test our game.
All right, let's go ahead and test out our flashlight here.
So when we hold it out, there we go.
We equip the flashlight.
And unfortunately, it doesn't look like our torso tilt is quite working right now which is a little
strange, but our flashlight should be tilting along with our torso.
We'll figure that out in a moment, but if we turn on the flashlight, there we go.
We have our bright light, and as you can see, our current battery is draining every two seconds.
If we unequip our flashlight, the flashlight turns off and we shouldn't have any battery drain.
So remember it was at 95.
So let's wait a couple of seconds and let's go ahead and check again.
Perfect.
The current battery is still at 95.
And now we can go ahead and turn our flashlight back on again and look around our map.
So our torso tilt is working, but unfortunately it looks like our other arm is not wanting to follow
along with the tilt of our torso, which is actually kind of strange.
So let me go ahead and figure out why exactly this isn't working, and we can get back to this in a
little bit.
All right.
After a little bit of digging, I actually figured out why our arm was not rotating with the direction
that we were looking.
And the reason was, is that there's an attribute inside of the workspace called retargeting.
And this is a property that you're going to want to disable.
Unfortunately, this property, when enabled, has some confliction when we try to rotate the keyframe
zero of different motor de constraints.
But by disabling this property, we can go ahead and fix that issue.
And now the animations will follow along with the rotation of the different motor 60s that you have
in your player's character.
So all you need to do inside of the workspace, you'll want to go into the properties section and go
down to where it says retargeting.
And you're going to want to change this from default to disabled.
And that should fix your issue with the rotation of the torso of the player.
So other than that, the next thing we need to do is script a system where batteries will spawn around
the map that players can collect to increase the charge of their flashlight when they are low or running
out of batteries.
So I'll go ahead.
See you in the next lecture.